/*
 自定义Promise 
 */


 (function(window){


    const STATUS_PENDING = 'pending';
    const STATUS_RESOLVED = 'resolved'
    const STATUS_REJECT = 'rejected'


    class Promise {
        constructor(excutor){
            const self = this;
            self.status = STATUS_PENDING;
            self.data = undefined;
            self.callbacks = []; // {onResolved() {}, onRejected(){}}
            
            function resolve(value){
                if(self.status !== STATUS_PENDING){
                    return;
                }
    
                self.status = STATUS_RESOLVED;
                self.data = value;
                
                if(self.callbacks.length > 0){
                    self.callbacks.forEach(calbacksObj => {
                        setTimeout(() => {
                            calbacksObj.onResolved(value);
                        }, 0);
                    });
                }
    
            }
    
            function reject(reason){
                if(self.status !== STATUS_PENDING){
                    return;
                }
    
                self.status = STATUS_REJECT;
                self.data = reason;
                
                if(self.callbacks.length > 0){
                    self.callbacks.forEach(calbacksObj => {
                        setTimeout(() => {
                            calbacksObj.onRejected(reason);
                        }, 0);
                    });
                }
            }
            try{
                excutor(resolve, reject);
            } catch(error){
                reject(error);
            }
    
        }
    
        then(onResolved, onRejected){
    
            onRejected = typeof onRejected === 'function' ? onRejected : reason=>{throw reason}
            onResolved = typeof onResolved === 'function' ? onResolved : value => value
             
            const self = this;
            return new Promise((resolve, reject)=>{
                function handle(callback){
                    try{
                        const result = callback(self.data);
                        if(result instanceof Promise){
                            // result.then(
                            //     value=>resolve(value),
                            //     reason => reject(reason)
                            // ); 
                            result.then(resolve, reject);
                        } else {
                            resolve(result);
                        }
                    } catch (error){
                        reject(error);
                    }
                }
                
                if(self.status === STATUS_PENDING){
                    self.callbacks.push({
                        onResolved(value){
                            handle(onResolved)
                        },
                        onRejected(reason){
                            handle(onRejected)
                        }
                    })
                } else if (self.status === STATUS_RESOLVED){
                    setTimeout(() => {
                        handle(onResolved);
    
                    }, 0);
                } else {
                    setTimeout(() => {
                        handle(onRejected);
                    }, 0);
                }
            });
        }
    
        catch(onReject){
            return this.then(undefined, onReject);
        }
    
        static resolve(value){
             return new Promise((resolve, reject)=>{
                if(value instanceof Promise){
                    value.then(resolve, reject);
                } else {
                    resolve(value);
                }
             });
        }
    
        static reject(reason){
            return new Promise((resolve, reject)=>{
                reject(reason);
            })
        }
    
        static all(promises){
            const values = new Array(promises.length);
            let resolvedCount = 0;
            return new Promise((resolve, reject)=>{
                promises.forEach((p, index)=>{
                    Promise.resolve(p).then(
                        value =>{
                            values[index] = value;
                            resolvedCount++;
                            if(resolvedCount == promises.length){
                                resolve(values);
                            }
                        },
                        reason => {
                            reject(reason);
                        }
                    )
                });
            });
        }
    
        static race(promises){
    
            return new Promise((resolve, reject)=>{
                promises.forEach((p)=>{
                    Promise.resolve(p).then(
                        value =>{
                            resolve(value);
                        },
                        reason => {
                            reject(reason);
                        }
                    )
                });
            });
        }
    
    
        static resolveDelay(value, time){
            return new Promise((resolve, reject)=>{
                setTimeout(() => {
                    if(value instanceof Promise){
                        value.then(resolve, reject);
                    } else {
                        resolve(value);
                    }                
                }, time);
             });
        }
    
        static rejectDelay(value, time){
            return new Promise((resolve, reject)=>{
                setTimeout(() => {
                    reject(value);
                }, time);
            })
        }
    
    }

    window.Promise = Promise;
 })(window)